Chapter 1:
Introduction

Welcome back to class. In the first lesson, we reviewed a lot of Java topics very briefly. I hope I gave enough detail to remind you of what you've already learned without boring you to death!

In this lesson, we're going to jump into a couple of those topics in more depth. We're going to spend some time with arrays and see how to use two different types of loops to process arrays easily and efficiently. While we're doing that, we're also going to go over how to write programs with more than one class.

With that said, let's jump into the deep water (just speaking figuratively there).

Chapter 2:
Array Structure

We discussed arrays briefly in the first Java course and even more briefly in the first lesson of this course. It's time to settle down and see what makes arrays work (and how to make them work for us)! Almost every programming language has some form of this data structure, which is a good sign that it's a very useful structure.

First, let's go over the definition of an array. In Java, an array is a group of elements of the same type that are stored together in memory and accessed by using an index. So as we discussed in the first lesson, an array name by itself refers to the array, while the name followed by an index refers to just one element of an array.

Since a picture is worth a thousand words, let me draw one of a hypothetical array here:

TQA-6 --- This drawing represents the memory where an array with n elements is stored. The array's elements are stored contiguously, and we can use them individually via the index in square brackets. For example, if the array stores character values, and its name is c, then using c in a program will refer to the array, while using c [0] will refer to the first character in the array; c [4] will refer to the fifth character, and c [n-1] will refer to the last character in the array.

Since there's no better way to learn something than to practice, let's develop a program that uses an array. Along the way, we'll learn about some other aspects of Java.

We'll start out simple. Let's say I want to keep a basketball team roster. (I haven't done this since my daughter finished playing college ball, but it's something I'm familiar with and can develop pretty easily. So I'm going with it.) To start with, we'll just make a list of the players on the team. How can we do that? (Hint: This is a lesson on arrays. It would be a good guess to plan on using one.)

Since we want to store the names of the players, we'll make it an array of strings. Just to make sure we have enough room, our default constructor will allow for 20 players on our imaginary team. So we'll declare our array like this:

String[] teamArray = new String[20];

Now, just to get a feel for how to use an array, we're going to write a simple program to allow a user to enter player names and print a roster. Let's start by making a class called Team that will store and retrieve our roster. Let me show you my first version of the class, then we'll go over the details of what it does and how. (Note that I'm leaving out many of the comments I would normally include in the interest of saving space.)

public class Team
{
    private String[] roster; // array for roster
    private int teamSize;    // number of players in roster


    public Team()
    {
        roster = new String[20]; // create array
        teamSize = 0;            // initialize team size
    }


    public Team(int arraySize)
    {
        roster = new String[arraySize]; // create array
        teamSize = 0;     // initialize team size
    }


    public void addPlayer(String playerName)
    {
        if (teamSize < roster.length)
        {
            roster[teamSize] = playerName; // add player to roster
            teamSize++;                    // increment team size
        }
    }


    public String toString()
    {
        String teamRoster = "Team Roster\n\n"; // output String
        int i = 0;                             // loop counter
        while (i < teamSize)                   // while more players
        {
            teamRoster = teamRoster + roster[i] + "\n"; // add name to roster
            i++;                               // increment loop counter
        }


        return teamRoster;                    // return roster
    }
}

Here's how the class works. The first two statements in the class declare a String array named roster to hold the team roster, and an int variable named teamSize to keep track of how many names are in the roster.

This is a good place to point out that once you create an array, its size is fixed. An array with 20 elements always has room for exactly 20 elements, whether you're using all or none of them. The only way to keep track of how many array elements actually contain information is to do it yourself. That's what we'll use the variable teamSize for.

Team Class Constructors

The default class constructor creates an array with room for 20 strings, then initializes the team size to zero. There's a second constructor that allows the client class to set the size of the array if 20 is too big or too small.

The addPlayer() Method

The addPlayer() method does two things if the array isn't already full. (The if statement checks for that by comparing the team size to the array size using a field that's built into every array in Java, the length field.) As long as there's room left in the array, the addPlayer() method puts the contents of the string argument playerName into the next available spot in the roster array. It uses the variable teamSize as the index pointing to the next spot.

Once the name is stored in the array, teamSize is incremented by one. The ++ operator in Java is called the increment operator, and it will add one to whatever variable you use it with.

The toString() Method

The toString() method formats the array's contents into an output string. This method is standard in many Java classes and is always designed to prepare the class's data for output. The toString() method does that for our Team class using a loop to process each name in the array with the index i, adding each name to the end of the output string named teamRoster. When used with strings, the plus sign becomes the concatenation operator, which concatenates, or links together, two strings by adding the second to the end of the first.

The other item that might be new to you is the \n in the string. That's the newline constant. Wherever it appears in a string is where a new line will begin when that string is displayed or printed.

If my explanation of this class leaves any questions in your mind,
please let me know in the Discussion Area and I'll be glad to explain more.

Chapter 3:
The Driver Program

Let me say just a word here about how we'll be coding programs in this course. The Team class isn't a complete program because there's no main() method. We've created this class without one. Its purpose is to build a team roster and to provide the roster in an output format, not to interact with a user. For that purpose, we'll create another class called a driver class, and we'll name it TeamDriver. This class will provide the main() method we need to have a complete program, and it will allow us to interact with the Team class and its capabilities. We can also use it to test the Team class very conveniently.

Here's the driver program that will use and test our Team class. After I show you the driver, we'll look at the output from running it.

public class TeamDriver
{
    public static void main(String[] args)
    {
        Team t = new Team(); 

        t.addPlayer("John Doe");
        t.addPlayer("Jack Spratt");
        t.addPlayer("Donald Duck");
        t.addPlayer("Bugs Bunny");
        t.addPlayer("Paul Bunyan");
        t.addPlayer("Pecos Bill");
        t.addPlayer("Rip van Winkle"); 

        System.out.println(t.toString());
     }
}

This simple driver does three things. First, it declares a Team reference named t and creates a default Team object for it to refer to. Second, it adds several players to the team using repeated calls to addPlayer(). Finally, it displays the roster built by the toString() method. As promised, here's the output of a run of this driver:



TeamDriver output

Creating a driver like this has several advantages. If we change the Team class for any reason, we can run this test again to make sure it still works. If we want to test other aspects of the class, like what happens if we try to add more players than the roster will hold, all we have to do is add more tests to the driver program. For example, we could create a smaller roster of five spots and add the same seven names to it. And if we want to build a set of tests to test every aspect of the class, we can put them all into one driver so we can rerun them whenever we want. Drivers are very common tools when testing classes, and we'll use them extensively in this course.

Okay! We have a class that uses an array to store and display a roster, and a driver program to test it. Now what?

Being the avid basketball fan that I am, I just decided that a roster of names is not enough. I want to store more information about the players on the team and be able to display it. There are at least two basic ways we could approach this. The first is to create a separate array for each piece of information about the players. Just like we have an array of their names, we could have a second array with their positions, a third one with their heights, a fourth one with average points per game, and so on. The advantage of doing it this way is that it's quick—all we have to do to add another statistic is add another array to the Team class along with ways to get the information in and out.

But this approach also has disadvantages: The number of arrays quickly becomes pretty clumsy, and we have the problem of coordinating the arrays to make sure that each player's information is in the same position in each array. Of course, these problems aren't critical, and this straightforward approach will work.

There's another approach, however, that will only use one array and keep the Team class much simpler. It will also make our lives easier, since we won't have to deal with a bunch of different arrays. (Have you seen how many statistics teams keep these days? We could easily end up with 15 or 20 arrays to keep straight!)

This second approach is simply to create another class to hold all the information about a single player and change the Team class to use an array of these new objects instead of an array of strings. Doesn't that sound so much easier?

The first thing to do is set up our new class, which we'll call Player. We need to decide what information to store about each player. Most teams track position, average points, rebounds, and assists per game, so let's use those. Here's a minimal Player class:

public class Player
{
    private String name;
    private char position;
    private double avgPoints;
    private double avgRebounds;
    private double avgAssists;

public Player(String pName, char pPos, double pPoints, double pRebounds, double pAssists) { name = pName; position = pPos; avgPoints = pPoints; avgRebounds = pRebounds; avgAssists = pAssists; } public String toString() { return "Player: " + name + "\n Position: " + position + "\n Points/Game: " + avgPoints + "\n Rebounds/Game: " + avgRebounds + "\n Assists/Game: " + avgAssists; } }

This is a minimal class because all it does is let us create and display player objects. If this were a class for real use, we would have edits on all the fields to make sure they were valid (no negative averages, no positions that don't exist, and so on). We would also have methods to allow changes as the season progressed. This class will do for our purposes, though. If you have any questions about what I didn't include, please ask me in the Discussion Area.

Now that we have a Player class, we need to change our Team class to use it. Let's go over the changes we need to make to Team, and then we'll look at a new listing of the class.

First, we need to change the type of the variable roster from String[] to Player[].

Second, in both constructors, we need to change the new String declaration to new Player.

Next, in the addPlayer() method, we need to change the parameter type from String to Player. Since the parameter is now a Player object instead of just a player's name, let's change the parameter name to player to better describe its contents. That means we need to change it in the method's header line and also four lines later, where it's used in the assignment statement.

The last change we need to make is in the toString() method, to the while loop where each array entry is concatenated to the roster text string. Instead of concatenating the array element (roster[i]), we want to concatenate the string returned by its toString() method, like this: roster[i].toString().

Our Team class now looks like this:

public class Team
{
    private Player[] roster; // array for roster
    private int teamSize;    // number of players in roster

public Team() { roster = new Player[20]; // create array teamSize = 0; // initialize team size }

public Team(int arraySize) { roster = new Player[arraySize]; // create array teamSize = 0; // initialize team size }

public void addPlayer(Player player) { if (teamSize < roster.length) { roster[teamSize] = player; // add player to roster teamSize++; // increment team size } }

public String toString() { String teamRoster = "Team Roster\n\n"; // output String int i = 0; // loop counter

while (i < teamSize) // while more players { teamRoster = teamRoster + roster[i].toString() + "\n"; // add to roster i++; // increment loop counter }

return teamRoster; // return roster } }

Now all we have to do is update our driver to match the new classes and try it out! To do that, we need to replace each player's name in the calls to addPlayer() with a complete player object. Since we'll only be using them to pass as arguments, we don't really need to save or name them, so we can put the new Player right into the method calls, like this:

public class TeamDriver
{
    public static void main(String[] args)
    {
        Team t = new Team();

t.addPlayer(new Player("John Doe",'C',19.19,15.15,4.4)); t.addPlayer(new Player("Jack Spratt",'F',11.11,7.7,3.3)); t.addPlayer(new Player("Donald Duck",'G',13.13,4.4,6.6)); t.addPlayer(new Player("Bugs Bunny",'G',8.8,2.2,1.1)); t.addPlayer(new Player("Paul Bunyan",'C',5.5,1.1,2.2)); t.addPlayer(new Player("Pecos Bill",'G',9.9,3.3,6.6)); t.addPlayer(new Player("Rip van Winkle",'F',8.0,4.0,2.0));

System.out.println(t.toString()); } }

Finally, here's what the output looks like from a run of our new driver using our new classes:




New TeamDriver output

Chapter 4:
for Loops

Now that we've played around with arrays a little bit, let's look at another improvement we can make to our classes. Specifically, we're going to focus on the while loop we used to build the output string for our team roster. It's in the Team class, right at the end, in the toString() method:

public String toString()
    {
        String teamRoster = "Team Roster\n\n"; // output String
        int i = 0;                             / loop counter

while (i < teamSize) // while more players { teamRoster = teamRoster + roster[i].toString() + "\n"; // add to roster i++; // increment loop counter }

return teamRoster; // return roster }

To make the loop work, I had to do three things. First, I had to set up a counter to keep track of how many players I had already added to the output string. I used a local variable named i for that. Second, each time through the loop, I had to check to see if i had reached the size of the team yet so I'd know when to stop. And third, I had to increment my counter i each time the loop ran. Wouldn't it be nice if there were a convenient loop form that let me do all that in one place instead of in three different lines of code? (Don't you just hate it when teachers ask rhetorical questions?)

Of course, since I asked that question, you already know there must be a more convenient form of a loop for me to use. It's called a for loop. It lets us do all three of those things in one statement. We use it most often when we want a counter to control a loop.

Since it's called a for loop, you might expect it to have the word for in it, and I won't disappoint you. Here is Java's for loop format:

for (<initialization>; <condition>; <increment>)
{
    // code for loop body goes here
}

The first line of this loop gives us all three of the items we used to control the while loop. The initialization is where we'll set the starting value for our counter. This part of the loop control is executed only once, at the beginning of the loop process.

The condition part of the line is where we put the condition that will control how many times the loop executes. Whatever condition we put there is tested at the beginning of each cycle through the loop to see if it's time to stop the loop yet. The loop will continue as long as the condition is true.

The last part of the line, the increment part, is also executed each time through the loop, but it's the last thing done.

There's one important format detail to notice in the for loop. We separate the different parts of the control with semicolons (;), not commas like other lists in Java.

To show you how it works, let's set up a for loop that's equivalent to the while loop we used in our method:

for (int i = 0; i < teamSize; i++)
{
    teamRoster = teamRoster + roster[i].toString() + "\n"; // add to roster
}

This loop does exactly what the while loop did. It sets up the counter i, compares it to the variable teamSize at the start of each iteration to see when to stop, and increments i at the end of each iteration. To put it in plain English, this loop will execute once for every value of i between zero and teamSize.

Here is the complete method with the loop modified to give you a better picture of how it looks:

public String toString()
{
    String teamRoster = "Team Roster\n\n"; // output String

for (int i = 0; i < teamSize; i++) // for all players { teamRoster = teamRoster + roster[i].toString() + "\n"; // add name to roster }


return teamRoster; // return roster }

By now you might be asking, "Why add another type of loop if the first one was good enough?" That's a good question. The answer is that programmers are just as lazy as anyone else, and this format makes their job a little easier by putting all the details of managing a loop in one place, especially a loop controlled by a counter.

I hope that made sense, because now I'm going to throw yet one more loop variation at you. (Then I'll quit, I promise!)

This last format is even simpler when working with a Java collection. Java has several forms of collections, and we'll see more of them in future lessons. For now, we'll define a collection as a group of things put together into one object. In Java, arrays are one form of collection, and that makes this last form of loop workable for us. With this loop format, we don't even have to keep a count or have a condition to test. Java will take care of all that for us.

TQA-4 --- The last loop format is often called the for-each loop since it runs once for each item in the collection, no matter how many there are. Java makes sure that each item in the collection is processed and that none of them are processed twice. Here's the format of the for-each loop:

for (<element> : <collection>)
{
    // code for loop body goes here
}

To describe this loop in English, we could say, "For each element in collection, execute the loop body." Let's set up our toString method one more time with this new loop type. Ideally we could set it up like as below. But if you run it that way, you'll get an error, so don't run it yet:

public String toString()
{
    String teamRoster = "Team Roster\n\n"; // output String

for (Player p : roster) // for each player in roster { teamRoster = teamRoster + p.toString() + "\n"; // add name to roster }


return teamRoster; // return roster }

The reason this would fail if you ran it is because for Player p : roster means "for each player in the roster array". But earlier in the Team class I said there would be "up to 20" players in a team by creating an array of 20 (initially empty) elements.

roster = new Player[20]; // create array
	

Then in TeamDriver, I only added 7 members to the team. To use the for…each loop, you would have to change that 20 to match the actual number of elements in the array like this:

roster = new Player[7]; // create array

If you make that change, compile, and run, then the code should run without an error.

As with most things in programming, there really isn't a "right way", "wrong way", "good way", "bad way" to do things. There are just different ways. In this last example, I had three choices for looping through the team players. The last one, of for…each, would just require that I change the code so that the initial array size match the actual number of elements in the array. In situations where that's not practical, just use a looping method that is practical for the occasion.

Chapter 5:
Summary

I hope you see how useful arrays can be in dealing with multiples of a single type of data. They're one of the most commonly used data structures in many programming languages, not just Java. Please take the time to make sure you understand how they work so you'll be able to make use of them, too.

Today we looked at how loops are very useful (necessary, in fact) when processing array elements. They often go hand-in-hand, so that's another reason to make sure you understand what we learned today.

In the next lesson, we'll take a look at some simple file input and output processes so we don't have to get all our input from the keyboard or hard-code it into a program like we did in our driver this time.

If you have any questions, please post them in the Discussion Area so I can answer them for you. And don't forget to complete the quiz and assignment for this lesson!

Until next time, then.

Lesson 2 FAQs

Q: Since the for-each loop processes every element in a collection, is there any reason to use a for loop?

A: Yes, for loops can easily control any process where a counter is used, and not all those processes deal with collections.

Lesson 2 Assignment

For your Lesson 2 assignment, I would like you to use an array to figure out which day of the week is the best for a fictional business. Write a program to ask a user for sales information. For each sale, have the user enter the day of the week and the amount of the sale. Store total sales for each day of the week in an array, and after the last sale is entered, list the sales for each day and tell which day had the highest sales.

If you are looking for a tougher challenge, you can also store the number of sales for each day and calculate the average amount of each sale for each day of the week.

To see one possible solution for this assignment, click the link below.

Assignment 2 Solution

Lesson 2 Quiz Answers

1. Which of the following declares and creates an array of 10 Boolean values named boolArray?
boolean[] boolArray = new boolean[10];

2. Which of the following references will return the first element of the array declared in question 1?
boolArray[0]

3. How can I find out the size of an array?
By using the array's length field.

4. Which of these is a loop that will execute its statements 10 times?
for (int i = 0; i < 10; i++)

5. Which of the following is a valid for-each loop to process all the elements in an array of Strings named elements?
for (String s : elements)